# -*- coding: utf-8 -*-
"""
    :author: FanZhong (范钟)
    :copyright: © 2018 FanZhong <coder.fan@qq.com>
    :license: MIT, see LICENSE for more details.
"""
import os
import logging
import click

from flask import Flask, request, render_template
from flask_wtf.csrf import CSRFError
from logging.handlers import SMTPHandler, RotatingFileHandler
from fblog.settings import config
from fblog.extensions import db, login_manager, csrf, ckeditor, mail, moment
from fblog.blueprints.blog import blog_bp
from fblog.blueprints.auth import auth_bp
from fblog.blueprints.admin import admin_bp
from fblog.models import Admin, Post, Category, Comment, Link

basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))


def create_app(config_name=None):
    if config_name is None:
        config_name = os.getenv('FLASK_CONFIG', 'development')

    app = Flask('fblog')
    app.config.from_object(config[config_name])
    register_extensions(app)
    register_logging(app)
    register_blueprints(app)
    register_errors(app)
    register_shell_context(app)
    register_commands(app)
    return app


def register_logging(app):
    class RequestFormatter(logging.Formatter):

        def format(self, record):
            record.url = request.url
            record.remote_addr = request.remote_addr
            return super(RequestFormatter, self).format(record)

    request_formatter = RequestFormatter(
        '[%(asctime)s] %(remote_addr)s requested %(url)s\n'
        '%(levelname)s in %(module)s: %(message)s'
    )

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    file_handler = RotatingFileHandler(os.path.join(basedir, 'logs/bluelog.log'),
                                       maxBytes=10 * 1024 * 1024, backupCount=10)
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.INFO)

    # 当错误的时候发送邮件
    mail_handler = SMTPHandler(
        mailhost=app.config['MAIL_SERVER'],
        fromaddr=app.config['MAIL_USERNAME'],
        toaddrs=['ADMIN_EMAIL'],
        subject='Bluelog Application Error',
        credentials=(app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD']))
    mail_handler.setLevel(logging.ERROR)
    mail_handler.setFormatter(request_formatter)

    if not app.debug:
        app.logger.addHandler(mail_handler)
    app.logger.addHandler(file_handler)


def register_extensions(app):
    # bootstrap.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    csrf.init_app(app)
    ckeditor.init_app(app)
    mail.init_app(app)
    moment.init_app(app)


def register_blueprints(app):
    app.register_blueprint(blog_bp)
    app.register_blueprint(admin_bp, url_prefix='/admin')
    app.register_blueprint(auth_bp, url_prefix='/auth')


def register_shell_context(app):
    @app.shell_context_processor
    def make_shell_context():
        return dict(db=db, Admin=Admin, Post=Post, Category=Category, Comment=Comment)


def register_errors(app):
    @app.errorhandler(400)
    def bad_request(e):
        return '400', 400
        # return render_template('errors/400.html'), 400

    @app.errorhandler(404)
    def page_not_found(e):
        return '404', 404
        # return render_template('errors/404.html'), 404

    @app.errorhandler(500)
    def internal_server_error(e):
        # return render_template('errors/500.html'), 500
        return '500', 500

    @app.errorhandler(CSRFError)
    def handle_csrf_error(e):
        return '400', 400
        # return render_template('errors/400.html', description=e.description), 400


def register_commands(app):
    @app.cli.command()
    @click.option("--drop", is_flag=True, help="创建和删除")
    def initdb(drop):
        if drop:
            click.confirm('这会删除数据库中的所有数据，是否继续？', abort=True)
            db.drop_all()
            click.echo('Drop tables.')
        db.create_all()
        click.echo("Initialized database.")

    @app.cli.command()
    @click.option("--username", prompt=True, help="请输入用户名")
    @click.option("--password", prompt=True, help="请输入密码")
    def init(username, password):
        click.echo("Initializing the database...")
        db.create_all()

        admin = Admin.query.first()
        if admin is not None:
            click.echo('The administrator already exists, updating...')
            admin.username = username
            admin.set_password(password)
        else:
            click.echo('Creating the temporary administrator account...')

            admin = Admin(
                username=username,
                blog_title="Fblog",
                blog_sub_title="No, I'm the real thing.",
                name='Admin',
                about='Anything about you.'
            )
            admin.set_password(password)
            db.session.add(admin)

        category = Category.query.first()
        if category is None:
            click.echo('Creating the default category...')
            category = Category(name='Default')
            db.session.add(category)

        db.session.commit()

        click.echo('Done.')
